﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace MechWars
{
    public class Polygon
    {
        public Color color = Color.White;
        public Vector2 origin = Vector2.Zero;
        public List<Vector2> vertexs = new List<Vector2>();
        public List<Vector2> normals = new List<Vector2>();
        Vector2 getNormal(Vector2 a, Vector2 b)
        {
            //finds the relative vector
            Vector2 c = b - a;
            //then it finds the perpendicular of that angle 90degs counter clockwise
            c = new Vector2(c.Y, -c.X);
            //then normalises it
            c.Normalize();
            return c;
        }
        public void AddVertex(Vector2 vertex)
        {
            //addes a vertex to the vertex list no work there
            vertexs.Add(vertex);
            //checks if the vertex list is 1 if it is 1 it means its is its first value
            if (vertexs.Count() == 1)
            {
                //if it is the first value then we know we can't make a normal from that so we just lie and say the normal is facing up
                normals.Add(Vector2.UnitX);
            }
            else
            {
                //now that we know that we have more then one value we can create the two normals
                //first it makes a normals from the last Value to the first
                normals.Add(getNormal(vertexs.Last<Vector2>(), vertexs.First<Vector2>()));
                //then connects the second to last to the last why? because the last cycle the second to last was the last and thus it pointed to the first
                normals[normals.Count() - 2] = getNormal(vertexs[vertexs.Count() - 2], vertexs.Last<Vector2>());
            }
        }
        public void RemoveVertex()
        {
            //simple enough remove one value from each list
            vertexs.RemoveAt(vertexs.Count - 1);
            normals.RemoveAt(normals.Count() - 1);
            //hears the tricky part well not really you simple have to if the list has less than zero values then you connect the first to the last
            if (normals.Count() > 0)
            {
                normals[normals.Count() - 1] = getNormal(vertexs.Last<Vector2>(), vertexs.First<Vector2>());
            }

        }
        static Vector2 projectToNormal(Polygon poly, Vector2 normal)
        {
            bool first = true;
            Vector2 minMax = Vector2.Zero;

            foreach (Vector2 vertex in poly.vertexs.ToArray())
            {
                float test = Vector2.Dot(vertex + poly.origin, normal);
                if (first)
                {
                    first = false;
                    minMax = new Vector2(test);
                }
                if (test > minMax.Y && !first)
                {
                    minMax.Y = test;
                }
                if (test < minMax.X && !first)
                {
                    minMax.X = test;
                }
            }
            return (Vector2)minMax;
        }
        static float dotDistance(Polygon a, Polygon b, Vector2 normal)
        {
            float distance = 0;
            Vector2 objAMinMax = projectToNormal(a, normal);
            Vector2 objBMinMax = projectToNormal(b, normal);
            distance = objAMinMax.X - objBMinMax.Y;
            return distance;
        }
        public static PhysicalInfo calPhysics(Player player, Polygon poly)
        {
            //detect collsion
            PhysicalInfo returnPhys = new PhysicalInfo();
            returnPhys.newPosition = player.position;
            returnPhys.newVelocity = player.velocity;
            if (player.flipped)
            {
                returnPhys.normal = new Vector2(0, -1);
            }
            else
            {
                returnPhys.normal = new Vector2(0, 1);
            }

            Vector2 minNormal = Vector2.Zero;
            Vector2 minNormalFloor = Vector2.Zero;
            float? minDist = null;
            bool stillChecking = true;
            //check the objects normals
            for (int i = 0; i < poly.vertexs.Count(); ++i)
            {

                float distCaled = dotDistance(player.collsionPoly, poly, poly.normals[i]);
                if (distCaled > 0)
                {
                    stillChecking = false;
                }
                else
                {
                    if (minDist == null)
                    {
                        minDist = distCaled;
                        minNormal = poly.normals[i];
                        minNormalFloor = minNormal;
                    }
                    if (minDist < distCaled)
                    {
                        minDist = distCaled;
                        minNormal = poly.normals[i];
                        minNormalFloor = minNormal;
                    }
                }
            }

            //check the players normals
            if (stillChecking)
            {
                for (int i = 0; i < player.collsionPoly.vertexs.Count(); ++i)
                {
                    float distCaled = dotDistance(player.collsionPoly, poly, player.collsionPoly.normals[i]);
                    if (distCaled > 0)
                    {
                        stillChecking = false;
                    }
                    else
                    {
                        if (minDist == null)
                        {
                            minDist = distCaled;
                            minNormal = player.collsionPoly.normals[i];
                        }
                        if (minDist < distCaled)
                        {
                            minDist = distCaled;
                            minNormal = player.collsionPoly.normals[i];
                        }

                    }
                }
            }
            if (stillChecking)
            {
                returnPhys.newVelocity = Vector2.Reflect(player.velocity, minNormal);
                returnPhys.newPosition += minNormal * -(float)minDist;
                if (player.flipped)
                {
                    returnPhys.normal = new Vector2(0, -1);
                    returnPhys.floor = minNormal.Y < -0.5f;
                    returnPhys.ceil = minNormal.Y > 0.5f;
                }
                else
                {
                    returnPhys.normal = new Vector2(0, 1);
                    returnPhys.floor = minNormal.Y > 0.5f;
                    returnPhys.ceil = minNormal.Y < -0.5f;
                }
                if (returnPhys.floor)
                {
                    returnPhys.normal = minNormal;
                    returnPhys.newVelocity *= 0;
                }
                if (returnPhys.ceil)
                {
                    returnPhys.newVelocity *= 0.5f;
                }
            }

            return returnPhys;

        }
    }
}
